package com.hui.config;


import com.hui.config.security.CustomAccessDeniedHandler;
import com.hui.config.security.CustomAuthenticationEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;

/**
 * 资源服务器配置类
 *
 * @author chenlei
 * @date 2022/6/21
 * @return
 **/
@Configuration
@EnableResourceServer // 标识为资源服务器，请求服务中的资源，就要带着token过来，找不到token或token是无效访问不了资源
@EnableGlobalMethodSecurity(prePostEnabled = true) // 开启方法级别权限控制
public class SecurityResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Value("${spring.security.oauth2.check-token-url}")
    private String checkTokenUrl;

    @Value("${spring.security.oauth2.client-id}")
    private String clientId;

    @Value("${spring.security.oauth2.client-secret}")
    private String clientSecret;

    @Autowired
    CustomAccessDeniedHandler customAccessDeniedHandler;

    @Autowired
    CustomAuthenticationEntryPoint customAuthenticationEntryPoint;

    /**
     * 配置资源服务器如何验证token有效性
     * 1. DefaultTokenServices
     * 如果认证服务器和资源服务器同一服务时,则直接采用此默认服务验证即可
     * 2. RemoteTokenServices (当前采用这个)
     * 当认证服务器和资源服务器不是同一服务时, 要使用此服务去远程认证服务器验证
     *   
     */
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        // 资源服务器去远程认证服务器验证 token 是否有效
        RemoteTokenServices service = new RemoteTokenServices();
        // 请求认证服务器验证URL，注意：默认这个端点是拒绝访问的，要设置认证后可访问
        service.setCheckTokenEndpointUrl(checkTokenUrl);
        // 在认证服务器配置的客户端id
        service.setClientId(clientId);
        // 在认证服务器配置的客户端密码
        service.setClientSecret(clientSecret);
        //因为采取redis存储token，因此要到授权服务器中验证token信息
        resources.tokenServices(service)
                //当用户传入无效的token会触发myAuthenticationEntryPoint的commence方法进行处理
                .authenticationEntryPoint(customAuthenticationEntryPoint)
                //当用户的权限不足时，customAccessDeniedHandler的handle方法进行处理
                .accessDeniedHandler(customAccessDeniedHandler)
                .resourceId("oauth-server-api2")
        ;
    }


    @Override
    public void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests(request -> {
            request.antMatchers(
                    "/sockjs-node/info/**",
                    "/cptp/doc.html",
                    "/cptp/swagger-resources/configuration/ui",
                    "/cptp/swagger-resources",
                    "/swagger-resources/**",
                    "/cptp/v2/api-docs",
                    "/v2/**",
                    "/doc.html",
                    "/webjars/**",
                    "/cptp/swagger-ui",
                    "/cptp/webjars/**",
                    "/cptp/api-docs").permitAll()
                    .anyRequest().authenticated()
            ;
        })
                //关闭csrf选项，防止他拦截post请求
                .csrf().disable()
                //基于token验证，关闭session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }


}
